home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / sharsrc.arc / shar.c < prev   
Encoding:
C/C++ Source or Header  |  1990-03-20  |  14.3 KB  |  630 lines

  1. /*
  2.  *  Shar puts readable text files together in a package
  3.  *  from which they are easy to extract.
  4.  *
  5.  *    v 860716 M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM
  6.  *    - enhanced usage message
  7.  *
  8.  *    v 860712 D. Wecker for ULTRIX and the AMIGA
  9.  *    - stripped down.. does patterns but no directories
  10.  *    - added a -u (unshar) switch
  11.  *
  12.  *    v 870128 R. Royar for ST
  13.  *    - removed #ifdefs that left stray }s in file
  14.  *    - reformatted text for consistant style
  15.  *    - modified main to abort when no files are given
  16.  *    - fixed call to fputc in tell macro, which omitted the stream
  17.  *      causing address errors on the ST.
  18.  *    - fixed STUPID coding in getopt that tried to write to
  19.  *      address 0++.
  20.  *    - known bugs:
  21.  *        still no directory support.  Extracting
  22.  *        files with directory names will get
  23.  *        only the directory name on an open call.
  24.  *
  25.  *    v 880713 J. Altstadt for ST
  26.  *    - removed extraneous #ifdefs for all other systems
  27.  *    - reformatted text for consistant style
  28.  *    - changed lots of things for unsharing:
  29.  *      1. added directory handling
  30.  *      2. added code to handle weird shar sed formats better,
  31.  *         will add more things when i get files that i can't unshar,
  32.  *         eg. when i get one of those icky sharchives that has split files
  33.  *         but won't add in the ability to handle shars that use awk to
  34.  *         extract files (yes, windsrch uses awk, blech!!!)
  35.  *      3. added in file overwrite protection, i didn't need it, but it was
  36.  *         easy (and i know i will need it some day when i don't have a
  37.  *         backup)
  38.  *      4. skip whitespace at begining of lines intended for sh, so it will
  39.  *         do stuff embedded in "if test" structures
  40.  *
  41.  *    v 890124 J. Altstadt for ST
  42.  *    - unshar will handle files split across two (or more) sharchives
  43.  *    - fixed bug that would allow creation of directories (files) with
  44.  *      the same name as an existing file (directory)
  45.  */
  46.  
  47.  
  48. #include <stdio.h>
  49. #include <osbind.h>
  50. #include <ctype.h>
  51. #include <stat.h>
  52.  
  53. long _stksize = 16 * 1024;    /* for 10k stack */
  54. char *Defenv = "ENOENV";    /* if no cc.ini file */
  55. extern char *getenv(),*malloc(),*index();
  56. void shar();
  57.  
  58.  
  59. #define BADCH    ((int)'?')
  60. #define EMSG    ""
  61. #define tell(s) {fputs(*nargv,stderr);fputs((s),stderr);fputc('\n',stderr);}
  62. #define rescanopts()    (optind = 1)
  63.  
  64. int    optind = 1,    /* index into parent argv vector */
  65.     optopt;        /* character checked for validity */
  66. long    fsize;        /* length of file */
  67. char    *optarg;    /* argument associated with option */
  68. char    *sav[100];    /* saved file names */
  69. int    savind;        /* save index */
  70.  
  71. /* OPTIONS */
  72. int    Verbose = 0;        /* provide append/extract feedback */
  73. int    Basename = 0;        /* extract into basenames */
  74. int    Count = 0;        /* count characters to check transfer */
  75. char    *Delim = "SHAR_EOF";    /* put after each file */
  76. char    Filter[100] = "cat";    /* used to extract archived files */
  77. char    *Prefix = NULL;        /* line prefix to avoid funny chars */
  78. int    OverWrite = 0;        /* do we overwrite an output file? */
  79.  
  80. char Usage1[] =
  81. "\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n\
  82. \n\
  83. usage: shar [[-uo] archive] [[-a] [-p prefix]\
  84.  [-d delim] [-bcv] files > archive]\n\
  85. \n\
  86.     where:    -a    all the options (v,c,b,-pXX)\n";
  87.  
  88. char Usage2[] =
  89. "        -b    extract absolute paths into current directory\n\
  90.         -c    check filesizes on extraction\n\
  91.         -d    use this EOF delimiter instead of SHAR_EOF\n";
  92.  
  93. char Usage3[] =
  94. "        -o    unshar <archive>, overwriting old files\n\
  95.         -p    use this as prefix to each line in archived files\n\
  96.         -u    unshar <archive>, not overwriting old files\n\
  97.         -v    verbose on extraction, incl. echoing filesizes\n";
  98.  
  99.  
  100. #define SED "sed 's/^%s//'"    /* used to remove prefix from lines */
  101. #define OPTSTRING "u:o:ap:d:bcv"
  102.  
  103.  
  104. void main(argc, argv)
  105. int argc;
  106. char **argv;
  107. {
  108.     char *ppchFiles[256];
  109.     register int    C;
  110.     char **ppchList = ppchFiles;
  111.     register int errflg;
  112.     errflg = 0;
  113.  
  114.     while(EOF != (C = getopt(argc, argv, OPTSTRING))) {
  115.         switch(C) {
  116.         case 'v':
  117.             Verbose++;
  118.             break;
  119.         case 'c':
  120.             Count++;
  121.             break;
  122.         case 'b':
  123.             Basename++;
  124.             break;
  125.         case 'd':
  126.             Delim = optarg;
  127.             break;
  128.         case 'a': /* all the options */
  129.             optarg = "X";
  130.             Verbose++;
  131.             Count++;
  132.             Basename++;
  133.             /* fall through to set prefix */
  134.         case 'p':
  135.             sprintf(Filter, SED, Prefix = optarg);
  136.             break;
  137.         case 'o':
  138.             OverWrite++;
  139.         case 'u':
  140.             dounshar(optarg);
  141.             exit(0);
  142.             break;
  143.         default:
  144.             errflg++;
  145.         }
  146.     }
  147.  
  148.     C = getarg(argc, argv);
  149.     if (errflg || EOF == C) {
  150.         if (EOF == C)
  151.             fprintf(stderr, "shar: No input files\n");
  152.         fprintf(stderr, "%s%s%s", Usage1, Usage2, Usage3);
  153.         exit(1);
  154.     }
  155.     savind = 0;
  156.  
  157.     do {
  158.         if (getpat(optarg)) exit(2);
  159.     } while (EOF != (C = getarg(argc, argv)));
  160.  
  161.     sav[savind] = 0;
  162.     header(sav);
  163.     for (ppchList = sav; *ppchList; ++ppchList)
  164.         shar(*ppchList);
  165.     puts("#\tEnd of shell archive");
  166.     puts("exit 0");
  167.     exit(0);
  168. }
  169.  
  170.  
  171. int header(ppchFiles)
  172. char *ppchFiles[];
  173. {
  174.     char clock[40];
  175.     register char **ppchList;
  176.     char *pchOrg;
  177.     char *pchName;
  178.     register int    problems;
  179.     problems = 0;
  180.     pchOrg = getenv("organization");
  181.     pchName = getenv("name");
  182.     puts("#\tThis is a shell archive.");
  183.     puts("#\tRemove everything above and including the cut line.");
  184.     puts("#\tThen run the rest of the file through sh.");
  185.     puts("#----cut here-----cut here-----cut here-----cut here----#");
  186.     puts("#!/bin/sh");
  187.     puts("# shar:    Shell Archiver");
  188.     puts("#\tRun the following text with /bin/sh to create:");
  189.     for (ppchList = ppchFiles; *ppchList; ++ppchList)
  190.         printf("#\t%s\n", *ppchList);
  191.     stime(clock);
  192.     printf("# This archive created: %s",clock);
  193.     if (pchName)
  194.         printf("# By:\t%s (%s)\n", pchName,pchOrg);
  195.     return(0);
  196. }
  197.  
  198.  
  199. /* create an ASCII time string and copy it into timeline.  Caller
  200.  * should make sure timeline has ~35 characters space.
  201.  */
  202. stime(timeline)
  203. char timeline[];
  204. {
  205.     register int mytime;
  206.     register int date;
  207.     register int hours, minutes, seconds;
  208.     int day, month, year;
  209.     static char *months[] = {"January","February","March","April",
  210.                 "May","June","July","August","September",
  211.                 "October","November","December"};
  212.     char *tzone;
  213.     tzone = getenv("timezone");
  214.     mytime    = Tgettime();
  215.     date = Tgetdate();
  216.     seconds = (mytime&31)*2;
  217.     minutes = (mytime>>5)&63;
  218.     hours    = (mytime>>11)&31;
  219.     day = (date&31);
  220.     month = ((date>>5)&15)-1;
  221.     year = ((date>>9)&31)+1980;
  222.     sprintf(timeline,"%02d-%s-%d %d:%02d:%02d %s\n",
  223.     day,months[month],year,hours,minutes,seconds,tzone);
  224.     return(1);
  225. }
  226.  
  227.  
  228. int
  229. archive(input, output)
  230. char *input, *output;
  231. {
  232.     char line[BUFSIZ];
  233.     register FILE *ioptr;
  234.  
  235.     if (ioptr = fopen(input, "r")) {
  236.         printf("%s << \\%s > %s\n", Filter, Delim, output);
  237.         while(fgets(line, BUFSIZ, ioptr)) {
  238.             if (Prefix)
  239.                 fputs(Prefix, stdout);
  240.             fputs(line, stdout);
  241.             if (Count)
  242.                 fsize += strlen(line);
  243.         }
  244.         puts(Delim);
  245.         fclose(ioptr);
  246.         return(0);
  247.     }
  248.     else {
  249.         fprintf(stderr, "shar: Can't open '%s'\n", input);
  250.         return(1);
  251.     }
  252. }
  253.  
  254.  
  255. void shar(file)
  256. char *file;
  257. {
  258.     register char *basefile;
  259.     basefile = file;
  260.     if (!strcmp(file, "."))
  261.         return;
  262.     fsize = 0;
  263.     if (Basename) {
  264.         while(*basefile)
  265.             basefile++;        /* go to end of name */
  266.         while(basefile > file && *(basefile-1) != '/')
  267.             basefile--;
  268.     }
  269.     if (Verbose)
  270.         printf("echo shar: extracting %s\n", basefile);
  271.     if (archive(file, basefile))
  272.         exit(66);
  273.     if (Count) {
  274.         printf("if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile);
  275.         printf("then\necho shar: error transmitting %s ",basefile);
  276.         printf("'(should have been %ld characters)'\nfi\n",fsize);
  277.     }
  278. }
  279.  
  280.  
  281. getpat(pattern)
  282. char *pattern;
  283. {
  284.     register char *ptr;
  285.  
  286.     ptr = pattern;
  287.     sav[savind] = malloc(strlen(ptr)+1);
  288.     strcpy(sav[savind++],ptr);
  289.     if (access(ptr,4)) {
  290.         printf("No read access for file: %s\n",ptr);
  291.         return(-1);
  292.     }
  293.     return(0);
  294. }
  295.  
  296.  
  297. /*
  298.  * get option letter from argument vector
  299.  */
  300. int
  301. getopt(nargc, nargv, ostr)
  302. int nargc;
  303. char **nargv, *ostr;
  304. {
  305.     register char    *oli;        /* option letter list index */
  306.     static char    *place = EMSG;    /* option letter processing */
  307.  
  308.     if(!*place) {            /* update scanning pointer */
  309.         if(optind >= nargc || *(place = nargv[optind])
  310.                 != '-' || !*++place)
  311.             return(EOF);
  312.         if (*place == '-') {    /* found "--" */
  313.             ++optind;
  314.             return(EOF);
  315.         }
  316.     }    /* option letter okay? */
  317.     if ((optopt = (int)*place++) == (int)':'
  318.             || !(oli = index(ostr,optopt))) {
  319.         if(!*place)
  320.             ++optind;
  321.         tell(": illegal option");
  322.     }
  323.     if (oli) {        /* %$^& what if oli = NULL!!! */
  324.         if (*++oli != ':') {        /* don't need argument */
  325.             optarg = NULL;
  326.             if (!*place)
  327.                 ++optind;
  328.         }
  329.         else {                /* need an argument */
  330.             if (*place)        /* no white space */
  331.                 optarg = place;
  332.             else {
  333.                 if (nargc <= ++optind) {    /* no arg */
  334.                     place = EMSG;
  335.                     tell(": option requires an argument");
  336.                 }
  337.                 else
  338.                     optarg = nargv[optind]; /*white space*/
  339.             }
  340.             place = EMSG;
  341.             ++optind;
  342.         }
  343.     }
  344.     return(optopt);         /* dump back option letter */
  345. }
  346.  
  347.  
  348. int
  349. getarg(nargc, nargv)
  350. int nargc;
  351. char **nargv;
  352. {
  353.     if (nargc <= optind) {
  354.         optarg = (char *) 0;
  355.         return(EOF);
  356.     }
  357.     else {
  358.         optarg = nargv[optind++];
  359.         return 0;
  360.     }
  361. }
  362.  
  363.  
  364. dounshar(ArcNam)
  365. char *ArcNam;
  366. {
  367.     register int i;
  368.     register FILE *inptr,*outptr;
  369.     register int hundreds;
  370.     char line[BUFSIZ];
  371.     int DirNum = -1;
  372.     int Prefix = 0;
  373.     char Dirs[10][40], FilNam[428], Delim[128], ScrStr[28];
  374.     char strip[40];
  375.     char *ptr, *lptr;
  376.     int wipeold, append, exists;
  377.     struct stat dirstat;
  378.  
  379.     if (!(inptr = fopen(ArcNam,"r"))) {
  380.         fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam);
  381.         return;
  382.     }
  383.     while (fgets(line, BUFSIZ, inptr)) {
  384.         for (lptr = line; (*lptr != (char) 0) && (isspace(*lptr));
  385.                 lptr++)
  386.             ;
  387.         if (strncmp(lptr, "sed ", 4) == 0) {
  388.             Prefix = 0;
  389.             strcpy(strip, "");
  390.             if (!(ptr = index(lptr,'/')))
  391.                 goto getfil;
  392.             if (*++ptr == '^')
  393.                 ++ptr;
  394.             while (*ptr != '/') {
  395.                 strncat(strip, ptr, 1);
  396.                 Prefix++;
  397.                 *(strip + Prefix) = (char) 0;
  398.                 ptr++;
  399.             }
  400.             goto getfil;
  401.         }
  402.         else if (strncmp(lptr, "gres ", 5) == 0) {
  403.             Prefix = 0;
  404.             strcpy(strip, "");
  405.             if (!(ptr = index(lptr,'\'')))
  406.                 goto getfil;
  407.             if (*++ptr == '^')
  408.                 ++ptr;
  409.             while (*ptr != '\'') {
  410.                 if (*ptr == '0')
  411.                     continue;
  412.                 strncat(strip, ptr, 1);
  413.                 Prefix++;
  414.                 *(strip + Prefix) = (char) 0;
  415.                 ptr++;
  416.             }
  417.             goto getfil;
  418.         }
  419.         else if (strncmp(lptr,"cat ",4) == 0) {
  420.             Prefix = 0;
  421. getfil:
  422.             FilNam[0] = 0;
  423.  
  424.             for (i = 0; i <= DirNum; i++) {
  425.                  strcat(FilNam,Dirs[i]);
  426.                 strcat(FilNam,"\\");
  427.             }
  428.  
  429.             append = 0;
  430.             getshpar(lptr, ">", ScrStr, 1);
  431.             if (strcmp(">", ScrStr) == 0) {
  432.                 getshpar(lptr, ">>", ScrStr, 1);
  433.                 append = 1;
  434.             }
  435.             strcat(FilNam,ScrStr);
  436.             getshpar(lptr, "<<", Delim, 0);
  437.             wipeold = 1;
  438.             exists = 1;
  439.  
  440.             i = stat(FilNam, &dirstat);
  441.             i = i < 0 ? i : (int) dirstat.st_mode;
  442.             if ((i >= 0) && (i <= 0X3F)) {
  443.                 if (!OverWrite)
  444.                     wipeold = 0;
  445.             }
  446.             else
  447.                 exists = 0;
  448.  
  449.             if (wipeold && !append) {
  450.                 outptr = fopen(FilNam, "w");
  451.                 fprintf(stderr, "Creating %s ", FilNam);
  452.             }
  453.             else if (append && exists) {
  454.                 outptr = fopen(FilNam, "a");
  455.                 fprintf(stderr, "Appending %s ", FilNam);
  456.             }
  457.             else if (append && !exists) {
  458.                 fprintf(stderr, "Cannot append to %s,\n\
  459. \tyou need to unshar another sharchive first ", FilNam);
  460.             }
  461.             else
  462.                 fprintf(stderr, "Will not overwrite %s ",
  463.                         FilNam);
  464.             if (!outptr) {
  465.                 fprintf(stderr, "Fatal:  could not open file \
  466. %s\n", FilNam);
  467.                 exit(1);
  468.             }
  469.             fflush(stderr);
  470.             hundreds = 0;
  471.             while (fgets(line, BUFSIZ, inptr)) {
  472.                 if (strncmp(line, Delim, strlen(Delim)) == 0)
  473.                     break;
  474.                 hundreds++;
  475.                 if (!(hundreds % 100)) {
  476.                     fprintf(stderr, ".");
  477.                     fflush(stderr);
  478.                 }
  479.                 if ((wipeold && !append) || (append && exists))
  480.                     if (strncmp(line, strip, Prefix))
  481.                         fputs(line, outptr);
  482.                     else
  483.                         fputs(&line[Prefix],outptr);
  484.             }
  485.             if (outptr) {
  486.                 fclose(outptr);
  487.                 fprintf(stderr,"done\n");
  488.             }
  489.             else {
  490.                 fprintf(stderr," error in creating file\n");
  491.                 exit(1);
  492.             }
  493.         }
  494.         else if (strncmp(lptr, "mkdir ", 6) == 0) {
  495.             FilNam[0] = 0;
  496.  
  497.             for (i = 0; i <= DirNum; i++) {
  498.                  strcat(FilNam,Dirs[i]);
  499.                 strcat(FilNam,"\\");
  500.             }
  501.  
  502.             getshpar(lptr, "mkdir", ScrStr, 1);
  503.             strcat(FilNam, ScrStr);
  504.  
  505.             i = stat(FilNam, &dirstat);
  506.             i = i < 0 ? i : (int) dirstat.st_mode;
  507.             if ((i >= 0) && (i <= 0X3F))
  508.                 if ((i & 0X10) == 0X10)
  509.                     continue;    /* don't re-create */
  510.                 else {
  511.                     fprintf(stderr, "will not mkdir %s,\n\
  512. \tthere is already a file of that name\n", FilNam);
  513.                     exit(1);
  514.                 }
  515.             if (Dcreate(FilNam)) {
  516.                 fprintf(stderr, "could not mkdir %s\n", FilNam);
  517.                 exit(1);
  518.             }
  519.         }
  520.         else if (strncmp(lptr,"cd ",3) == 0) {
  521.             if (lptr[3] == '.' && lptr[4] == '.')
  522.                 DirNum--;
  523.             else if (DirNum >= 9)
  524.                 fprintf(stderr,"directories nested too deep\n");
  525.             else {
  526.                 DirNum++;
  527.                 getshpar(lptr, "cd", ScrStr, 1);
  528.                 strcpy(Dirs[DirNum], ScrStr);
  529.             }
  530.             if (DirNum < -1)
  531.                 DirNum = -1;
  532.         }
  533.         else if (strncmp(lptr, "chdir ", 6) == 0) {
  534.             if (lptr[6] == '.' && lptr[7] == '.')
  535.                 DirNum--;
  536.             else if (DirNum >= 9)
  537.                 fprintf(stderr,"directories nested too deep\n");
  538.             else {
  539.                 DirNum++;
  540.                 getshpar(lptr, "cd", ScrStr, 1);
  541.                 strcpy(Dirs[DirNum], ScrStr);
  542.             }
  543.             if (DirNum < -1)
  544.                 DirNum = -1;
  545.         }
  546.     }
  547.     fclose(inptr);
  548. }
  549.  
  550.  
  551. getshpar(line, sea, par, flipslash)
  552. char *line, *sea, *par;
  553. int flipslash;
  554. {
  555.     register char *scr1, *scr2;
  556.  
  557.     while (*line) {
  558.         scr1 = line;
  559.         scr2 = sea;
  560.         while (*scr1 && *scr2 && *scr1 == *scr2) {
  561.             scr1++;
  562.             scr2++;
  563.         }
  564.         if (*scr2 == 0) {
  565.             if (*scr1 == 0) {
  566.                 *par = 0;
  567.                 return;
  568.             }
  569.             while (*scr1 == ' ' || *scr1 == '\t' ||
  570.                     *scr1 == '\\' || *scr1 == '\'' ||
  571.                     *scr1 == '"')
  572.                 scr1++;
  573.             while (*scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
  574.                     *scr1 != '\\' && *scr1 != '\'' &&
  575.                     *scr1 != '"' && *scr1 != '\n' &&
  576.                     *scr1 != '\r') {
  577.                 if ((*scr1 == '/') && flipslash) {
  578.                     *par++ = '\\';
  579.                     scr1++;
  580.                 }
  581.                 else
  582.                     *par++ = *scr1++;
  583.             }
  584.             if (*(par - 1) == '\\')    /* if \ at end, not ST path */
  585.                 par--;
  586.             *par = 0;
  587.             return;
  588.         }
  589.         line++;
  590.     }
  591.     *par = 0;
  592. }
  593.  
  594.  
  595. /* since nothing ever initializes the environment table on the ST
  596.  * I'll just use my home brew cc.ini environment file.
  597.  */
  598. char *getenv(var)
  599. register char *var;
  600. {
  601.     FILE *fp;
  602.     register char *ptr;
  603.     static char line[81];
  604.     register char *safestore;
  605.  
  606.     if ((fp=fopen("cc.ini","r")) == NULL)
  607.         return(Defenv);
  608.     while (fgets(line,80,fp)) {
  609.         if ((ptr=index(line,' '))!=(char *)NULL)
  610.             *ptr = '\0';
  611.         if ((ptr=index(line,'\n'))!=(char *)NULL)
  612.             *ptr = '\0';
  613.         if ((ptr=index(line,'\t'))!=(char *)NULL)
  614.             *ptr = '\0';
  615.         if ((ptr=index(line,'='))!=(char *)NULL)
  616.             *ptr = '\0';
  617.         else
  618.             continue;
  619.         ++ptr;
  620.         if (strcmp(line, var) == 0) {
  621.             safestore = malloc(strlen(ptr)+1);
  622.             strcpy(safestore,ptr);
  623.             return(safestore);
  624.         }
  625.         else if (feof(fp))
  626.             break;
  627.     }
  628.     return(Defenv);
  629. }
  630.